/**
 * @file Controlador.java
 * @brief Implementa la clase Controlador
 * 
 * Implementa la clase Controlador, encargada de realizar las operaciones
 * principales del sistema
 * 
 * @author Grupo de ISIII
 * @version 03.05
 * 
 */

package Controlador;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import org.jfree.chart.*;
import org.jfree.data.*;

import Definiciones.*;
import GestorCitas.*;
import GestorClinico.*;
import GestorUsuarios.*;
import GestorFarmacia.*;
import GestorPruebas.*;
import java.awt.Color;
import java.util.Arrays;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.SystemColor;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.DefaultPieDataset;

import java.awt.Font;


public class Controlador {

	private static Usuario _usuario_actual = null;

	public static Usuario getUsuarioActivo() {
		return _usuario_actual;
	}

	/**
	 * @brief Da de alta a un usuario
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String altaUsuario(String dniPasaporte, String nombre,
			String apellidos, GeneroUsuario genero, String correo,
			Direccion[] direcciones, int telefonoMovil, Date fechaNacimiento,
			TipoUsuario tipoUsuario, String login, String password, Rol rol)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {

		// Creamos e inicializamos objeto Usuario
		Usuario u = new Usuario();
		u.setDniPasaporte(dniPasaporte);
		u.setNombre(nombre);
		u.setApellidos(apellidos);
		u.setFechaNacimiento(fechaNacimiento);
		u.setGenero(genero);
		u.setCorreo(correo);
		u.setTelefonoMovil(telefonoMovil);
		u.setLogin(login);
		u.setPassword(Usuario.encriptarCadena(password));
		u.setEstado(EstadoUsuario.ACTIVO);
		u.setTipo(tipoUsuario);

		try {
			Usuario.add(u);
		} catch (SQLException e) {
			return "Error al intentar dar de alta al usuario.";
		} catch (IDException e) {
			return "El usuario fue dado de alta, pero no pudo se recuperado su id";
		}

		if (direcciones != null)
			for (Direccion d : direcciones) {
				try {
					Direccion.add(d);
					DireccionDAO.setDireccionUsuario(u.getIdUsuario(), d);
				} catch (SQLException e) {
					return "Error al crear o asignar direccion.";
				} catch (IDException e) {
					return "La direccion fue dada de alta, pero no pudo se recuperado su id";
				}
			}

		Bitacora bitacora = new Bitacora(Calendar.getInstance().getTime(),
				OperacionBitacora.ALTA, u.getIdUsuario(), _usuario_actual
						.getIdUsuario());
		try {
			Bitacora.add(bitacora);
		} catch (SQLException e) {
			return "Error al crear bitacora.";
		} catch (IDException e) {
			return "La bitacora fue dada de alta, pero no pudo se recuperado su id";
		}

		if (u.getTipo() == TipoUsuario.MEDICO && rol != null) {
			try {
				RolDAO.setRol(u.getIdUsuario(), rol.getNombre());
			} catch (SQLException e) {
				return "No se pudo establecer su rol.";
			}
		}

		return null;

	}

	/**
	 * @brief Modifica a un usuario
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String modificarUsuario(int idUsuario, String dniPasaporte,
			String nombre, String apellidos, GeneroUsuario genero,
			String correo, Direccion[] direcciones, Integer telefonoMovil,
			Date fechaNacimiento, TipoUsuario tipoUsuario,
			EstadoUsuario estadoUsuario, Rol rol)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {

		Usuario u;
		try {
			u = Usuario.get(idUsuario);
		} catch (SQLException e2) {
			return "Eror al intentar obtener el usuario.";
		}

		if (dniPasaporte != null)
			u.setDniPasaporte(dniPasaporte);
		if (nombre != null)
			u.setNombre(nombre);
		if (apellidos != null)
			u.setApellidos(apellidos);
		if (fechaNacimiento != null)
			u.setFechaNacimiento(fechaNacimiento);
		if (genero != null)
			u.setGenero(genero);
		if (correo != null)
			u.setCorreo(correo);
		if (telefonoMovil != null)
			u.setTelefonoMovil(telefonoMovil);
		if (estadoUsuario != null)
			u.setEstado(estadoUsuario);
		if (tipoUsuario != null)
			u.setTipo(tipoUsuario);

		try {
			Usuario.update(u);
		} catch (SQLException e1) {
			return "Error al intentar actualizar el usuario.";
		}

		try {
			u.deleteDirecciones();
		} catch (SQLException e1) {
			return "Error al intentar modificar las direcciones del usuario.";
		}
		if (direcciones != null)
			for (Direccion d : direcciones) {

				try {
					Direccion.add(d);
					DireccionDAO.setDireccionUsuario(u.getIdUsuario(), d);
				} catch (SQLException e) {
					return "Error al crear o asignar direccion.";
				} catch (IDException e) {
				}

			}

		if (u.getTipo() == TipoUsuario.MEDICO && rol != null) {
			try {
				((Medico) u).deleteRol();
			} catch (SQLException e) {
				return "Error al intentar eliminar el anterior rol del usuario.";
			}
			try {
				RolDAO.setRol(u.getIdUsuario(), rol.getNombre());
			} catch (SQLException e) {
				return "No se pudo establecer su rol.";
			}
		}
		return null;

	}

	/**
	 * @brief Da de baja a un usuario
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String bajaUsuario(int idUsuario)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {
		Usuario u;
		try {
			u = Usuario.get(idUsuario);
		} catch (SQLException e) {
			return "Error al intentar obtener el usuario.";
		}
		u.setEstado(EstadoUsuario.BAJA_DEFINITIVA);
		try {
			Usuario.update(u);
		} catch (SQLException e1) {
			return "Error al intentar actualizar el usuario.";
		}

		// Si es paciente...
		if (u.getTipo() == TipoUsuario.PACIENTE) {
			Paciente paciente = (Paciente) u;
			Cita[] citas = null;
			try {
				citas = paciente.getCitas(null, null, EstadoCita.PENDIENTE);
			} catch (SQLException e) {
				return "Error al intentar obtener citas. Cancelarlas manualmente";
			}

			if (citas != null)
				for (Cita c : citas) {
					if (c.getEstado() == EstadoCita.PENDIENTE) {
						c.setEstado(EstadoCita.CANCELADA);

						try {
							Cita.update(c);
						} catch (SQLException e) {
							return "Error al actualizar el estado de alguna de las citas.";
						}
					}
				}

		}

		// Si es medico...
		else if (u.getTipo() == TipoUsuario.MEDICO) {
			Medico medico = (Medico) u;
			Cita[] citas = null;
			try {
				citas = medico.getCitas(null, null);
			} catch (SQLException e) {
				return "Error al intentar obtener citas. Cancelarlas manualmente";
			}

			if (citas != null)
				for (Cita c : citas) {
					if (c.getEstado() == EstadoCita.PENDIENTE) {
						Medico[] medicos;
						try {
							medicos = UsuarioDAO.getMedicosDisponibles(c
									.getFechaCita(), c.getFechaFinalizacion());
						} catch (SQLException e1) {
							return "Error al intentar obtener los medicos sin cita.";
						}
						if (medicos == null) {
							return "No hay médicos para reubicar alguna de las citas.";
						}

						Random rnd = new Random();
						int sel = rnd.nextInt(medicos.length);
						Medico med_asignado = medicos[sel];
						c.setIdMedico(med_asignado.getIdUsuario());

						try {
							Cita.update(c);
						} catch (SQLException e) {
							return "Error al actualizar el estado de alguna de las citas.";
						}
					}
				}

		}

		Bitacora bitacora = new Bitacora(Calendar.getInstance().getTime(),
				OperacionBitacora.BAJA, u.getIdUsuario(), _usuario_actual
						.getIdUsuario());
		try {
			Bitacora.add(bitacora);
		} catch (SQLException e) {
			return "Error al crear bitacora.";
		} catch (IDException e) {
			return "La bitacora fue dada de alta, pero no pudo se recuperado su id";
		}

		return null;
	}

	/**
	 * @brief Autentifica al usuario
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String autentificarme(String login, String password)
			throws NoSuchAlgorithmException, SQLException, IOException,
			ClassNotFoundException {

		Usuario[] us = Usuario.get(null, login, null, null, null,
				EstadoUsuario.ACTIVO);
		// Comprueba si se encontro el usuario
		if (us == null)
			return "El usuario no existe.";

		// Comprueba si la contraseña es correcta
		if (us[0].getPassword().equals(Usuario.encriptarCadena(password))) {
			_usuario_actual = us[0];
			return null;
		} else
			return "Contraseña incorrecta.";

	}

	/**
	 * @brief Obtiene un usuario por su id.
	 * @return El usuario. Null si no lo encuentra.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static Usuario verDatosUsuario(int idUsuario)
			throws NoSuchAlgorithmException, SQLException, IOException,
			ClassNotFoundException {
		return Usuario.get(idUsuario);
	}

	/**
	 * @brief Cambia la contraseña del usuario
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String cambiarContrasenya(int idUsuario,
			String antiguoPassword, String nuevoPassword)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {

		if (nuevoPassword == null || nuevoPassword.length() < 6)
			return "La nueva contraseña no es válida, minimo seis caracteres.";

		Usuario u;
		try {
			u = Usuario.get(idUsuario);
		} catch (SQLException e) {
			return "Error al obtener el usuario.";
		}

		if (!Usuario.encriptarCadena(antiguoPassword).equals(u.getPassword()))
			return "El password no coincide con el del usuario.";

		u.setPassword(Usuario.encriptarCadena(nuevoPassword));
		try {
			Usuario.update(u);
		} catch (SQLException e) {
			return "Error al intentar actualizar el usuario.";
		}

		return null;
	}

	/**
	 * @brief Pide una cita
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String pedirCita(int idPaciente, Date fechaHora)
			throws NoSuchAlgorithmException, SQLException, IOException,
			ClassNotFoundException, IDException {
		
		if(fechaHora.before(Calendar.getInstance().getTime()))
			return "No se pueden pedir citas en fechas ya pasadas.";
		
		Usuario usuario = Usuario.get(idPaciente);
		if (usuario.getTipo() != TipoUsuario.PACIENTE) {
			return "El id no es de un paciente.";
		}

		Paciente paciente = (Paciente) usuario;
		Cita[] citas = paciente.getCitas(null, null, EstadoCita.PENDIENTE);
		if (citas != null) { // Ya habia citas
			return "El paciente ya tiene citas pendientes.";
		}

		Calendar cal = Calendar.getInstance();
		cal.setTime(fechaHora);
		cal.add(Calendar.MINUTE, 9);	// Las citas duran 9 minutos, para evitar solapamientos
		Date fechaFin = cal.getTime();

		UsuariosDisponibles[] medicos = UsuarioDAO.getMedicosDisponiblesOptimizado(fechaHora, fechaFin);
		if (medicos == null) {
			return "No hay médicos para atender la petición en ese horario.";
		}

		Random rnd = new Random();
		int sel = rnd.nextInt(medicos[0].getArrayId().size());
		int med_asignado = medicos[0].getArrayId().get(sel);

		Cita cita = new Cita(fechaHora, fechaFin, EstadoCita.PENDIENTE,null,
				paciente.getIdUsuario(), med_asignado, 0);
		Cita.add(cita);

		return null;
	}

	/**
	 * @brief Anula una cita
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String anularCita(int idCita) throws SQLException,
			IOException, ClassNotFoundException, IDException {

		Cita cita = Cita.get(idCita);
		if (cita == null) {
			return "No se ha encontado la cita.";
		}

		if (cita.getEstado() != EstadoCita.PENDIENTE) {
			return "La cita no está en estado pendiente para cancelarla.";
		}

		cita.setEstado(EstadoCita.CANCELADA);
		Cita.update(cita);

		return null;
	}

	/**
	 * @brief Pasa cita
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String pasarCita(int idCita, Date fechaIni, Date fechaFin,
			EstadoCita estado , String observaciones) throws IOException, ClassNotFoundException {

		Cita cita;
		try {
			cita = Cita.get(idCita);
		} catch (SQLException e) {
			return "Error al intentar obtener la cita.";
		}
		if (cita == null) {
			return "No se ha encontado la cita.";
		}

		if (_usuario_actual.getIdUsuario() != cita.getIdMedico()) {
			return "Esta cita no corresponde a este médico.";
		}

		if (fechaIni != null)
			cita.setFechaCita(fechaIni);
		if (fechaFin != null)
			cita.setFechaFinalizacion(fechaFin);
		if (estado != null)
			cita.setEstado(estado);

                cita.setObservaciones(observaciones);

		try {
			Cita.update(cita);
		} catch (SQLException e) {
			return "Error al intentar actualizar el estado de la cita.";
		}

		return null;
	}

	/**
	 * @brief Obtiene las citas de un usuario o un medico
	 * @return Una lista de citas o null si no encuentra nada.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static Cita[] consultarCitas(int idUsuario, Date fechaIni,
			Date fechaFin, EstadoCita estado) throws NoSuchAlgorithmException,
			IOException, ClassNotFoundException {

		if (idUsuario != -1) {
			Usuario usuario;
			try {
				usuario = Usuario.get(idUsuario);
			} catch (SQLException e1) {
				return null;
			}

			if (usuario.getTipo() == TipoUsuario.MEDICO)
				try {
					return Cita.get(null, usuario.getIdUsuario(), null,
							fechaIni, fechaFin, estado);
				} catch (SQLException e) {
					return null;
				}

			if (usuario.getTipo() == TipoUsuario.PACIENTE)
				try {
					return Cita.get(usuario.getIdUsuario(), null, null,
							fechaIni, fechaFin, estado);
				} catch (SQLException e) {
					return null;
				}
		} else {
			try {
				return Cita.get(null, null, null, fechaIni, fechaFin, estado);
			} catch (SQLException e) {
				return null;
			}
		}

		return null;

	}

	/**
	 * @brief Reubica una cita
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String reubicarCita(int idCita, int idMedico, Date fechaCita)
			throws SQLException, IOException, ClassNotFoundException,
			IDException {
		Cita cita = Cita.get(idCita);
		if (cita == null)
			return "Cita no encontrada.";

		cita.setIdMedico(idMedico);
		cita.setFechaCita(fechaCita);

		Calendar cal = Calendar.getInstance();
		cal.setTime(fechaCita);
		cal.add(Calendar.MINUTE, 9);	// Las citas duran 9 minutos para evitar solapamientos
		Date fechaFin = cal.getTime();
		cita.setFechaFinalizacion(fechaFin);

		Cita.update(cita);

		return null;

	}

	/**
	 * @brief Busca usuarios por parametros
	 * @return Una lista de usuarios encontrados. Null en otro caso.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static Usuario[] buscarUsuarios(Integer idUsuario, String login,
			String dniPasaporte, String nombre, String apellidos,
			TipoUsuario tipoUsuario, EstadoUsuario estado, Rol rol)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {
		Usuario[] usuarios;
		try {
			usuarios = Usuario.get(dniPasaporte, login, nombre, apellidos,
					tipoUsuario, estado);
		} catch (SQLException e) {
			return null;
		}
		if (rol == null) // Si no buscamos por rol, devolver lo obtenido
			return usuarios;
		// Si buscamos por rol
		String elRol = rol.getNombre();
		ArrayList<Usuario> usu_final = new ArrayList<Usuario>();
		for (Usuario u : usuarios) {
			if (u.getTipo() == TipoUsuario.MEDICO) {// No tenemos en cuenta los
				// que no sean medicos
				String suRol;
				try {
					suRol = RolDAO.getRol(u.getIdUsuario()).getNombre();
				} catch (SQLException e) {
					return null;
				}
				if (suRol.equals(elRol)) {
					usu_final.add(u);
				}
			}
		}

		if (usu_final.size() > 0) {
			usuarios = new Medico[usu_final.size()];
			usu_final.toArray(usuarios);
			return usuarios;
		} else
			return null;

	}

	/**
	 * @brief Cierra sesion
	 */
	public static void cerrarSesion() {
		_usuario_actual = null;
	}

	/**
	 * @brief Genera una nueva contraseña
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String[] generarNuevoPassword(int idUsuario)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {
		String[] res = new String[2];
		res[0] = new String();
		res[1] = new String();

		String nuevoPassword = "";

		Usuario u = null;
		try {
			u = Usuario.get(idUsuario);
		} catch (SQLException e) {
			res[0] = "Error al intentar obtener el usuario.";
			return res;
		}

		nuevoPassword += u.getDniPasaporte() + u.getNombre().substring(0, 2);
		u.setPassword(Usuario.encriptarCadena(nuevoPassword));
		try {
			Usuario.update(u);
		} catch (SQLException e) {
			res[0] = "Error al intentar asignar contraseña, no se han realizado cambios.";
			return res;
		}

		res[0] = null;
		res[1] = nuevoPassword;
		return res;

	}

	/**
	 * @brief Ficha la entrada de un trabajador
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 * @throws SQLException
	 */
	public static String ficharEntrada() throws NoSuchAlgorithmException,
			IOException, ClassNotFoundException {
		PersonalClinica per = (PersonalClinica) _usuario_actual;

		ControlHorario ch;
		try {
			ch = per.getUltimoControlHorario();
		} catch (SQLException e1) {
			return "Error al intentar fichar. Vuelva a intentarlo.";
		}
		if (ch != null) {

			if (ch.getFechaEntrada().equals(ch.getFechaSalida())) {
				return "Error al intentar fichar. Hay una operacion fichar salida pendiente.";
			}
		}

		try {
			per.ficharEntrada(Calendar.getInstance().getTime());
		} catch (SQLException e) {
			return "Error al intentar fichar. Vuelva a intentarlo.";
		}
		return null;
	}

	/**
	 * @brief Ficha la salida de un trabajador
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 * @throws SQLException
	 */
	public static String ficharSalida() throws NoSuchAlgorithmException,
			IOException, ClassNotFoundException {

		PersonalClinica per = (PersonalClinica) _usuario_actual;
		ControlHorario ch;
		try {
			ch = per.getUltimoControlHorario();
		} catch (SQLException e1) {
			return "Error al intentar fichar. Vuelva a intentarlo.";
		}

		if (ch == null)
			return "Error al intentar fichar. No hay ninguna operacion de fichar entrada realizada todavia";
		else {
			if (!ch.getFechaEntrada().equals(ch.getFechaSalida())) {
				return "Error al intentar fichar. No hay ninguna operacion de fichar entrada realizada todavia";
			}
		}

		try {
			per.ficharSalida(Calendar.getInstance().getTime());
		} catch (SQLException e) {
			return "Error al intentar fichar. Vuelva a intentarlo.";
		}

		return null;

	}

	/**
	 * @brief Asigna un turno de trabajo a un trabajador
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static String asignarTurno(int idPersonal, HoraTrabajo[] horas)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {

		try {
			Usuario u = Usuario.get(idPersonal);
		} catch (SQLException e) {
			return "Error al intentar obtener el usuario.";
		}

		if (horas == null)
			return "No se especificaron horas de trabajo.";

		try {
			HoraTrabajoDAO.setHoraTrabajoEmpleado(idPersonal, horas);
		} catch (SQLException e) {
			return "Error al intentar asignar la hora de trabajo.";
		} catch (IDException e) {
		}

		return null;
	}

	/**
	 * @brief Obtiene el horario de un usuario
	 * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static HoraTrabajo[] miHorario(int idPersonal)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {

		try {
			Usuario u = Usuario.get(idPersonal);
		} catch (SQLException e) {
			return null;
		}

		HoraTrabajo[] horaTrabajo;
		try {
			horaTrabajo = HoraTrabajo.getHorasTrabajo(idPersonal, null);
		} catch (SQLException e) {
			return null;
		}

		return horaTrabajo;
	}

	/**
	 * @brief Consulta los trabajadores en una hora
	 * @return Lista de usuarios encontrados. Null si no encuentra nada.
	 * @throws NoSuchAlgorithmException
	 *             , ClassNotFoundException, IOException
	 */
	public static Usuario[] consultarHorario(DiaSemana dia, String hora)
			throws NoSuchAlgorithmException, IOException,
			ClassNotFoundException {

		Integer[] id_usuarios = null;

		try {
			id_usuarios = HoraTrabajo.getPersonalClinica(dia, hora);
		} catch (SQLException e) {
			return null;
		}

		if (id_usuarios == null)
			return null;
		if (id_usuarios.length == 0)
			return null;

		Usuario[] usuarios = new Usuario[id_usuarios.length];

		for (int i = 0; i < id_usuarios.length; i++) {
			try {
				usuarios[i] = Usuario.get(id_usuarios[i]);
			} catch (SQLException e) {
				return null;
			}
		}

		return usuarios;
	}

        
        /**
	 * @brief Realiza la operación de recetar. Debe realizar la receta, añadir sus
         *        líneas y crear la información de las entregas.
	 * @return NULL, si se modificó el medicamento con éxito | Mensaje de error.
	 * @throws SQLException, IOException, ClassNotFoundException
         * @author Miguel Ángel Díaz López
	 */
        public static String recetar(Integer id_cita, String instrucciones, String juicioDiagnostico,
                                     LineaReceta[] lineas_receta) throws IOException, ClassNotFoundException, ParseException, SQLException{
            Integer id_receta = null;
            DateFormat fecha_formato = new SimpleDateFormat("yyyy-MM-dd");
            DateFormat Yformat = new SimpleDateFormat("yyyy");
            DateFormat Mformat = new SimpleDateFormat("MM");
            DateFormat Dformat = new SimpleDateFormat("dd");
            Integer year, month, day;
            Calendar cal_fecha = Calendar.getInstance();
            int dias_caja;
            
            /* Creamos y añadimos la receta */
            Receta r =  new Receta(null, instrucciones, juicioDiagnostico, id_cita);
            try {
                Receta.add(r);
            } catch (SQLException ex) {
                return "Error al intentar crear la nueva receta.";
            }
            Receta[] v_recetas;
            try {
                v_recetas = Receta.get(instrucciones, juicioDiagnostico, id_cita);
            } catch (SQLException ex) {
                return "Error al intentar obtener el identificador de la receta creada.";
            }
            id_receta = v_recetas[v_recetas.length-1].getIdReceta();

            /* Creamos y añadimos las líneas de receta correspondientes */
            if (lineas_receta != null) {
                for(int i=0; i<lineas_receta.length; i++){
                    lineas_receta[i].setIdReceta(id_receta);
                    try {
                        LineaReceta.add(lineas_receta[i]);
                    } catch (SQLException ex) {
                        return "Error al intentar crear la nueva línea de receta.";
                    }
                    if (lineas_receta[i].getIdLinea() < 0){
                        try {
                            LineaReceta[] l_recetas = LineaReceta.get(lineas_receta[i].getIdReceta(), lineas_receta[i].getIdMedicamento(), lineas_receta[i].getFechaInicio(),
                                                                      lineas_receta[i].getObservaciones(), lineas_receta[i].getCada(), lineas_receta[i].getTiempoCada(),
                                                                      lineas_receta[i].getEstaCancelada(), lineas_receta[i].getNumTomas());
                            lineas_receta[i].setIdLinea(l_recetas[l_recetas.length-1].getIdLinea());
                        } catch (SQLException ex) {
                            return "Error al intentar obtener el identificador de la línea de receta creada.";
                        }

                    }

                    /* Creamos información referente a la entrega de dicha receta */
                    Date f = lineas_receta[i].getFechaInicio();
                    year = Integer.parseInt(Yformat.format(f).toString());
                    month = Integer.parseInt(Mformat.format(f).toString());
                    day = Integer.parseInt(Dformat.format(f).toString());
                    Medicamento m = Medicamento.get(lineas_receta[i].getIdMedicamento());
                    if(m==null)
                        return "La línea de receta contiene un medicamento no dado de alta en la base de datos.";
                    Integer dosis_totales = m.getDosisPorUnidad();
                    Integer num_tomas = lineas_receta[i].getNumTomas();
                    Float cada = lineas_receta[i].getCada();
                    String tiempo = lineas_receta[i].getTiempoCada().toString().toLowerCase();
                    
                    /* Errores */
                    if(num_tomas == null || num_tomas <= 0)
                        return "La línea de receta tiene mal establecida el número de tomas.";
                    if(cada == null || cada <= 0)
                        return "La línea de receta tiene mal establecida el intervalo para cada toma.";
                    if(dosis_totales == null || dosis_totales <= 0)
                        return "El medicamento tiene mal establecido el número de dosis de la caja";

                    /* Guardamos las entregas en la BD */
                    while ( num_tomas > 0 ){
                        num_tomas -= dosis_totales;
                        String fecha = year.toString() + "-" + month.toString() + "-" + day.toString();
                        Entrega e = new Entrega(null,fecha_formato.parse(fecha),lineas_receta[i].getIdLinea(),null,Definiciones.Estado.PENDIENTE);
                        try {
                            Entrega.add(e);
                        } catch (SQLException ex) {
                            return "Error al intentar crear la nueva entrega.";
                        }
                        /* Siguiente fecha? */
                        if(tiempo.equals("horas")){
                            Float horas = cada*dosis_totales;
                            dias_caja = (horas.intValue()) / 24;
                            if (dias_caja*24 != horas) dias_caja++;
                        } else { // Días
                            dias_caja = ((Float)(cada*dosis_totales)).intValue();
                            if(cada*dosis_totales*10 != dias_caja*10)dias_caja++;
                        }
                        cal_fecha.setTime(fecha_formato.parse(year.toString() + "-" + month.toString() + "-" + day.toString()));
                        cal_fecha.add(Calendar.DAY_OF_YEAR, dias_caja);
                        year = Integer.parseInt((Yformat.format(cal_fecha.getTime())).toString());
                        month = Integer.parseInt((Mformat.format(cal_fecha.getTime())).toString());
                        day = Integer.parseInt((Dformat.format(cal_fecha.getTime())).toString());
                    }
                }
            } else {
                return "La receta no contiene ninguna \"línea de receta\" adjunta";
            }
            return null;
        }



        /*********
        /* Operaciones del sistema para la Farmacia */
        /*********
        /**
	 * @brief Modifica los datos de un medicamento del sistema.
	 * @return null, indica si se modificó el medicamento con éxito. | Mensaje error!
	 * @throws IOException, ClassNotFoundException
         * @author Miguel Ángel Díaz López
	 */
        public static String modificarMedicamento ( Integer id_medicamento, Definiciones.ATC cat, String nombre,
                                                    String DCIoMarca, Definiciones.ViaAdministracion via, Integer dosis,
                                                    Integer umbral, Integer cantidad_tipica, Definiciones.Estado estado) throws IOException, ClassNotFoundException {
            Medicamento m = null;
            try {
                m = Medicamento.get(id_medicamento);
            } catch (SQLException ex) {
               return "Error al intentar buscar el medicamento especificado en la base de datos.";
            }
            if (m != null) { // Existe en la BD
                if(m.getCategoriaMedicamento() != null && cat != null){
                    m.setCategoriaMedicamento(cat);
                }
                if(m.getNombreMedicamento() != null  && nombre != null){
                    m.setNombreMedicamento(nombre);
                }
                if(m.getDCI() != null  && DCIoMarca != null){
                    m.setDCI(DCIoMarca);
                }
                if(m.getViaAdministracion() != null  && via != null){
                    m.setViaAdministracion(via);
                }
                if(m.getDosisPorUnidad() != null  && dosis != null){
                    m.setDosisPorUnidad(dosis);
                }
                if(m.getUmbralExistenciasMedicamento() != null  && umbral != null){
                    m.setUmbralExistenciasMedicamento(umbral);
                }
                if(m.getCantidadTipicaMedicamento() != null  && cantidad_tipica != null){
                    m.setCantidadTipicaMedicamento(cantidad_tipica);
                }
                if(m.getEstadoMedicamento() != null  && estado != null){
                    m.setEstadoMedicamento(estado);
                }
            } else { //No existe en la BD
                return "Error el medicamento especificado no existe en la base de datos.";
            }
            try {
                Medicamento.update(m);
            } catch (SQLException ex) {
                return "Error al intentar actualizar el medicamento.";
            }
            return null;
        }

        
        /**
	 * @brief Buscar medicamentos según varios criterios de búsqueda.
	 * @return Lista de medicamentos encontrados. Null si no encuentra nada.
	 * @throws SQLException, IOException, ClassNotFoundException
         * @author Miguel Ángel Díaz López
	 */
	public static Medicamento[] buscarMedicamento ( Integer id_medicamento, Definiciones.ATC cat, String nombre,
                                                        String DCIoMarca, Definiciones.ViaAdministracion via, Integer dosis,
                                                        Integer umbral, Integer cantidad_tipica, Definiciones.Estado estado) throws SQLException, IOException, ClassNotFoundException {
            if (id_medicamento != null) {
                Medicamento[] m = null;
                Medicamento m_ = Medicamento.get(id_medicamento);
                if ( m_ != null) {
                    m = new Medicamento[1];
                    m[0] = m_;
                    return m;
                }
                else return m;
            }
            return Medicamento.get(cat, nombre, DCIoMarca, via, dosis, umbral, cantidad_tipica, estado);
        }


       /**
	 * @brief Cambia el estado de una entrega.
	 * @return NULL, si se modificó el medicamento con éxito.
         * @throws IOException, ClassNotFoundException
         * @author Miguel Ángel Díaz López
	 */
        public static String gestionarEstadoEntrega(Integer id_entrega, Definiciones.Estado estado) throws IOException, ClassNotFoundException{
            Entrega e;
            try {
                e = Entrega.get(id_entrega);
            } catch (SQLException ex) {
                return "Error al intentar obtener la entrega para cambiarle el estado.";
            }
            if (e == null) {
                return "La entrega no se encuentra en la base de datos";
            }
            e.setEstadoEntrega(estado);
            try {
                Entrega.update(e);
            } catch (SQLException ex) {
                return "Error al intentar actualizar el estado de la entrega.";
            }

            return null;
        }

        
        /**
         * @author Francisco Manuel Herrero Perez
         * @brief Da de alta un medicamento en el sistema con estado disponible
         * @param categoria Categoría del medicamento (ATC)
         * @param nombre Nombre del medicamento
         * @param DCI Marca del medicamento
         * @param via_admin Via de administrar el med.
         * @param dosis_unidad Nº de dosis que contiene cada envase
         * @param umbral_existencias Cantidad mínima recomendable de "stock"
         * @param cantidad_tipica "Stock" típico
         * @return null si se ha dado de alta correctamente o error si no se ha dado de alta
         * @throws SQLException
         * @throws IOException
         * @throws ClassNotFoundException
         */
        public static String altaMedicamento(Definiciones.ATC categoria, String nombre,
                                       String DCI, Definiciones.ViaAdministracion via_admin,
                                       Integer dosis_unidad, Integer umbral_existencias,
                                       Integer cantidad_tipica) throws SQLException, IOException, ClassNotFoundException {

            Medicamento m = new Medicamento(null, categoria, nombre, DCI, via_admin, dosis_unidad, umbral_existencias, cantidad_tipica, Definiciones.Estado.DISPONIBLE);
            try {
                Medicamento.add(m);  
            } catch (SQLException e) {
		return "Error al intentar dar de alta el medicamento.";
            }

            return null;
        }


        /**
         * @author Francisco Manuel Herrero Perez
         * @brief Da de alta un lote en la base de datos
         * @param estado Estado del lote
         * @param fecha_caducidad Fecha de caducidad del lote
         * @param fecha_llegada Fecha de llegada del lote a la farmacia
         * @param unidades_iniciales Unidades iniciales del lote
         * @param unidades_restantes Unidades que quedan del lote
         * @param id_medicamento Codigo del medicamento del lote
         * @return null si se ha dado de alta correctamente
         * @throws IOException
         * @throws ClassNotFoundException
         */
        public static String altaLote(Date fecha_caducidad, Date fecha_llegada,
                Integer unidades_iniciales, Integer unidades_restantes, Integer id_medicamento) throws IOException, ClassNotFoundException {

            Lote l = new Lote(null, unidades_iniciales, unidades_restantes, fecha_llegada,
                fecha_caducidad, Definiciones.Estado.DISPONIBLE, id_medicamento);
            try {
                Lote.add(l);
            } catch (SQLException e) {
                return "Error al intentar dar de alta el lote.";
            }

            return null;
        }


        /**
         * @author Francisco Manuel Herrero Pérez
         * @return Array de medicamentos con existencias bajas o null en caso
         * de que no existan medicamentos con bajas existencias en este momento(error)
         * @throws SQLException
         * @throws IOException
         * @throws ClassNotFoundException
         * @throws ParseException
         */
        public static Medicamento[] consultarBajasExistencias() throws SQLException, IOException, ClassNotFoundException, ParseException {
            return Medicamento.getBajasExistencias();
        }


        /**
         * @author Francisco Manuel Herrero Perez and Miguel Angel Diaz Lopez
         * @brief Obtiene las entregas asociadas a un paciente
         * @param id_paciente Codigo del paciente del que queremos obtener sus entregas
         * @return Array con las entregas del paciente @param id_paciente
         * o null en caso de error
         * @throws SQLException
         * @throws IOException
         * @throws ClassNotFoundException
         * @throws ParseException
         */
         public static Entrega[] obtenerEntregas(int id_paciente) throws SQLException, IOException, ClassNotFoundException, ParseException{
            ArrayList<Receta> recetas = new ArrayList<Receta>();
            ArrayList<Entrega> l_entregas = new ArrayList<Entrega>();
            Entrega[] v_entrega = null;
            Receta[] v_recetas = null;
            ArrayList<LineaReceta> l_linea_receta = new ArrayList<LineaReceta>();
            LineaReceta[] v_linea_receta = null;
            Cita [] citas =  Cita.get(id_paciente, null, null, null, null, null);
            
            if (citas == null) return null; // Error!
            for(int i = 0; i < citas.length; i++) {
                v_recetas = Receta.get(null, null, citas[i].getIdCita());
                if(v_recetas != null)
                    recetas.addAll(Arrays.asList(v_recetas));
            }
            
            if(recetas.size() < 1)  return null; // Error
            v_recetas = new Receta[recetas.size()];
            recetas.toArray(v_recetas);
            for(int i=0; i<v_recetas.length; i++){
                v_linea_receta = LineaReceta.get(v_recetas[i].getIdReceta(), null, null, null, null, null, null, null);
                if(v_linea_receta != null)
                    l_linea_receta.addAll(Arrays.asList(v_linea_receta));
            }

            if(l_linea_receta.size() < 1)   return null; // Error
            v_linea_receta = new LineaReceta[l_linea_receta.size()];
            l_linea_receta.toArray(v_linea_receta);
            v_entrega = Entrega.get(null, null, Definiciones.Estado.PENDIENTE);
            if(v_entrega == null) return null;//error!
            for(int i=0; i < v_entrega.length;i++){
                for(int j=0; j<v_linea_receta.length; j++)
                    if(v_entrega[i].getIdLineaReceta() == v_linea_receta[j].getIdLinea())
                        l_entregas.add(v_entrega[i]);
            }
            v_entrega = new Entrega[l_entregas.size()];
            l_entregas.toArray(v_entrega);

            return v_entrega;
        }


        /**
	 * @brief Borrado lógico de un medicamento. Su estado pasa a ser "No disponible"
	 * @return NULL, si se modifica el estado del medicamento y un mensaje de error en caso contrario
         * @throws IOException, ClassNotFoundException
         * @author Ana Ferreira Blanco
	 */
        public static String bajaMedicamento(Integer id) throws IOException, ClassNotFoundException {
            Medicamento m = null;
            try {
                m = Medicamento.get(id);
            } catch (SQLException ex) {
               return "Error: no se encontró el medicamento.";
            }
            if (m != null) { // Existe en la BD
                if(m.getEstadoMedicamento() != null){
                    m.setEstadoMedicamento(Definiciones.Estado.NO_DISPONIBLE);
                }
            } else { //No existe en la BD
                return "Error: el medicamento no existe en la Base de Datos.";
            }
            try {
                Medicamento.update(m);
            } catch (SQLException ex) {
                return "Error al actualizar el medicamento.";
            }
            return null;
        }


        /**
	 * @brief Actualización del estado de un Lote de medicamentos.
	 * @return NULL, si se modifica el estado del lote y un mensaje de error en caso contrario
         * @throws IOException, ClassNotFoundException, ParseException
         * @author Ana Ferreira Blanco
	 */
        public static String cambiarEstadoLote(Integer id, Definiciones.Estado estado) throws IOException, ClassNotFoundException, ParseException {
            Lote lote = null;
            try {
                lote = Lote.get(id);
            } catch (SQLException ex) {
               return "Error: no se encontró el lote.";
            }
            if (lote != null) { // Existe en la BD
                if(lote.getEstadoLote() != null){
                    lote.setEstadoLote(estado);
                }
            } else { //No existe en la BD
                return "Error: el lote no existe en la Base de Datos.";
            }
            try {
                Lote.update(lote);
            } catch (SQLException ex) {
                return "Error al actualizar el lote.";
            }
            return null;
        }


        /**
	 * @brief Listado de las recetas de un paciente.
	 * @return Una lista de recetas  o un mensaje de error si no se encuentra el paciente.
         * @throws IOException, ClassNotFoundException
         * @author Fruela Palacio Pérez & revisada por: Miguel Ángel Díaz López
	 */
        public static Receta[] obtenerRecetas(Integer idPaciente)throws IOException, ClassNotFoundException, ParseException, SQLException{
            Receta[] v_recetas =null;
            ArrayList<Receta> l_recetas = new ArrayList<Receta>();

            Cita[] cita = Cita.get(idPaciente, null, null, null, null, null);
            if(cita == null)return null;
            for(int i = 0; i < cita.length; i++) {
                v_recetas = Receta.get(null, null, cita[i].getIdCita());
                if(v_recetas != null)
                    l_recetas.addAll(Arrays.asList(v_recetas)); // Obtenemos lista de recetas
            }
            // Convertimos la lista de recetas a vector de recetas
            v_recetas = new Receta[l_recetas.size()];
            l_recetas.toArray(v_recetas);
            
            return v_recetas;
        }


       /**
	 * @brief Listado del stock de medicamentos Disponibles.
	 * @return NULL, si se modifica el estado del medicamento y un mensaje de error en caso contrario
         * @throws IOException, ClassNotFoundException
         * @author Fruela Palacio Pérez
	 */
        public static Lote[] listarStock()throws IOException, ClassNotFoundException, ParseException, SQLException {
            return Lote.get(null, null, null, null, null, Definiciones.Estado.DISPONIBLE);
        }


       /**
	 * @brief Listado del stock de medicamentos.
	 * @return Lista con los lotes caducados
         * @throws IOException, ClassNotFoundException
         * @author Fruela Palacio Pérez
	 */
        public static Lote[] consultarLotesCaducados(Date fecha)throws IOException, ClassNotFoundException, ParseException, SQLException{
            return Lote.getLotesCaducados(fecha);
        }


        /**
	 * @brief Actualización de la información de un lote.
	 * @return NULL, si se modifica la información del lote y un mensaje de error en caso contrario
         * @throws IOException, ClassNotFoundException, ParseException
         * @author Ana Ferreira Blanco
	 */
        public static String modificarLote(Integer id, Definiciones.Estado estado, Date fecha_caducidad, Date fecha_llegada,
                  Integer unidades_iniciales, Integer unidades_restantes,Integer id_medicamento)
                  throws IOException, ClassNotFoundException, ParseException {
            Lote lote = null;
            try {
                lote = Lote.get(id);
            } catch (SQLException ex) {
               return "Error: no se encontró el lote.";
            }
            if (lote != null) { // Existe en la BD
                if(lote.getUnidadesInicialesLote() != null && unidades_iniciales != null){
                    lote.setUnidadesInicialesLote(unidades_iniciales);
                }
                if(lote.getUnidadesRestantesLote() != null  && unidades_restantes != null){
                    lote.setUnidadesRestantesLote(unidades_restantes);
                }
                if(lote.getFechaLlegadaLote() != null  && fecha_llegada != null){
                    lote.setFechaLlegadaLote(fecha_llegada);
                }
                if(lote.getFechaCaducidadLote() != null  && fecha_llegada != null){
                    lote.setFechaCaducidadLote(fecha_caducidad);
                }
                if(lote.getEstadoLote() != null && estado !=  null){
                    lote.setEstadoLote(estado);
                }
                if(lote.getIdMedicamento() != null && id_medicamento != null){
                    lote.setIdMedicamento(id_medicamento);
                }
            } else { //No existe en la BD
                return "Error: el lote no existe en la Base de Datos.";
            }
            try {
                Lote.update(lote);
            } catch (SQLException ex) {
                return "Error al actualizar el lote.";
            }
            return null;
        }


       /**
	 * @brief Convertimos la fecha (DATE) a algo legible para el usuario
	 * @return String con la fecha convertida.
         * @author Miguel Ángel Díaz López
	 */
        public static String mostrarFecha(Date fecha) {
            DateFormat Yformat = new  SimpleDateFormat("yyyy");
            DateFormat Mformat = new  SimpleDateFormat("MM");
            DateFormat Dformat = new  SimpleDateFormat("dd");
            DateFormat Hourformat = new  SimpleDateFormat("HH:mm:ss");
            String fech = "Hoy "+Dformat.format(fecha)+" de "+ Definiciones.convertirMes(Integer.parseInt(Mformat.format(fecha).toString()))+" del "+Yformat.format(fecha);
            String hora = "a las "+Hourformat.format(fecha)+" Horas";
            return (fech+", "+hora);
        }


        /**
         * @brief Crea una prueba
         * @return Pruebas encontradas. Null en otro caso
         * @throws SQLException, IOException,
         *  ClassNotFoundException, NoSuchAlgorithmException, IDException
         * @author Antonio M. Gutierrez Martinez
         */
        public static String asignarPruebas( Integer idCita , Integer idPaciente,
                Integer idMedico, Prueba[] pruebas ) throws SQLException, IOException,
            ClassNotFoundException, NoSuchAlgorithmException, IDException {

            for (Prueba p: pruebas){
                p.setIdCita(idCita);
                p.setIdMedico(idMedico);
                p.setIdPaciente(idPaciente);
                try {
                    Prueba.add(p);
                }catch (SQLException ex){
                    System.out.println("Fallo SQL:"+ex.getMessage());
                    return "asignarPruebas.No existe conexion con la BD. Compruebe su conexion a internet";
                }
            }

            return null;
            
        }


        /**
         * @brief Consulta las pruebas de un paciente.
         * @return Pruebas encontradas. Null en otro caso
         * @throws SQLException, IOException,
         *  ClassNotFoundException, NoSuchAlgorithmException, IDException
         * @author Antonio M. Gutierrez Martinez
         */
        public static Prueba[] consultarPruebas( Integer idCita , Integer idPaciente , Integer idMedico
                , Integer idTecnico , Date fecha
                , TipoPrueba t, EstadoPrueba e ) throws SQLException, IOException,
            ClassNotFoundException, NoSuchAlgorithmException, IDException, ParseException {

            try {
                return Prueba.get(idCita, idMedico, idPaciente, idTecnico, e, t, fecha,fecha);
            }catch (SQLException ex){
                System.out.println("Fallo SQL:"+ex.getMessage());
                return null;
            }
        }

        /**
         * Consulta los resultados de una prueba de una paciente
         * @return Prueba encontrada. Null en otro caso
         * @throws SQLException, IOException,
         *  ClassNotFoundException, NoSuchAlgorithmException, IDException
         * @author Antonio M. Gutierrez Martinez
         */
        public static Prueba consultarResultadosPaciente(  Integer idPrueba )
        //public static Prueba consultarResultadosPaciente( Integer idPaciente , Date fecha ,tipoPrueba t)
                throws IOException, ClassNotFoundException, IDException, NoSuchAlgorithmException, ParseException {
            try {
                return Prueba.get(idPrueba);
            }catch (SQLException ex){
                System.out.println("Fallo SQL:"+ex.getMessage());
                return null;
            }
        }

        /**
         * Habilita una prueba para ver sus resultados por parte del paciente.
         * @return String que indica el resultado de la operacion
         * @throws SQLException, IOException,
         *  ClassNotFoundException, NoSuchAlgorithmException, IDException
         * @author Antonio M. Gutierrez Martinez
         */
        public static String habilitarResultado( Integer idPrueba )
                throws IOException, ClassNotFoundException, IDException, NoSuchAlgorithmException, ParseException {
            Prueba p = null;
            String msg = "";
            try {
                p = Prueba.get(idPrueba);
            }catch (SQLException ex){
                System.out.println("habilitarResultado.Fallo SQL:"+ex.getMessage());
                return "Fallo de conexion con la base de datos";
            }

            if (p != null ) {
                if (p.getEstadoPrueba() == EstadoPrueba.Realizada) {
                    p.setEstadoPrueba(EstadoPrueba.Visualizable);
                    try {
                        Prueba.update(p);
                    }catch (SQLException ex){
                        System.out.println("habilitarResultado. Fallo SQL:"+ex.getMessage());
                        return "Fallo de conexion con la base de datos";
                    }
                    msg = "Operacion realizada con éxito";
                }else
                    msg = "La prueba todavia no se ha realizado";
            }else
                msg = "No se encontro la prueba";


            return msg;
        }

        /**
         * @brief Obtiene las fechas disponibles
         * @param inicio
         * @param fin
         * @return
         * @throws IOException
         * @throws ClassNotFoundException
         * @throws IDException
         * @throws NoSuchAlgorithmException
         */
        public static UsuariosDisponibles[] concertarPrueba( Date inicio , Date fin )
                throws IOException, ClassNotFoundException, IDException, NoSuchAlgorithmException{
            try {
                return Prueba.getFechasDisponibles(inicio, fin);
            }catch (SQLException ex){
                System.out.println("concertarPrueba.Fallo SQL:"+ex.getMessage());
                return null;
            }
        }

        /**
         * @brief Consulta las observaciones de un paciente
         * @param idPaciente
         * @return
         * @throws IOException
         * @throws ClassNotFoundException
         * @throws IDException
         * @throws NoSuchAlgorithmException
         */
        public static String consultarObservacionesPaciente( Integer idPaciente )
                throws IOException, ClassNotFoundException, IDException, NoSuchAlgorithmException{
            Usuario u = null;
            try {
                u = Usuario.get(idPaciente);
            }catch (SQLException ex){
                System.out.println("consultarObservacionesPaciente.Fallo SQL:"+ex.getMessage());
                return "Error al conectar con la base de datos.";
            }

            if ( u != null)
                return u.getObservaciones();
            else
                return "No hay ningun paciente.";

        }


        /**
         * @brief Modifica las observaciones de un paciente
         * @param idPaciente
         * @param observaciones
         * @return String con el resultado de la operacion
         * @throws IOException
         * @throws ClassNotFoundException
         * @throws IDException
         * @throws NoSuchAlgorithmException
         */
        public static String modificarObservacionesPaciente( Integer idPaciente, String observaciones )
                throws IOException, ClassNotFoundException, IDException, NoSuchAlgorithmException{
            Usuario u = null;
            //buscamos al usuario
            try {
                u = Usuario.get(idPaciente);
            }catch (SQLException ex){
                System.out.println("modificarObservaciones.Fallo SQL:"+ex.getMessage());
                return "Error al conectar con la base de datos.";
            }

            //Si hemos encontrado algo
            if ( u != null) {
                if ( u.getTipo() != TipoUsuario.PACIENTE)
                    return "El usuario no es un paciente";

                //Actualizamos
                u.setObservacioenes(observaciones);
                try {
                    Usuario.update(u);
                }catch (SQLException ex){
                    System.out.println("modificarObservaciones.Fallo SQL:"+ex.getMessage());
                    return "Error al conectar con la base de datos.";
                }
            } else
                return "No hay ningun paciente.";

            return "Operacion realizada con exito";
        }
        
       /**
        * @brief Cancelamos una prueba de un paciente
        * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
        * @throws NoSuchAlgorithmException, ClassNotFoundException, IOException, IDException,
        * @author Juan José Alonso Sánchez y Antonio M. Gutierrez Martinez
        */
        public static String cancelarPrueba(int idPrueba)
                throws SQLException,IOException, ClassNotFoundException, IDException, 
                NoSuchAlgorithmException,
                ParseException
        {
            Prueba prueba = null ;

            try {
                prueba = Prueba.get(idPrueba);
            }catch(SQLException e){
                System.out.println("cancelarPrueba.Fallo SQL:"+e.getMessage());
                return "Error al conectar con la base de datos";
            }

            if(prueba != null) {
                    return "No se ha encontado la prueba.";
            }else {
                if(prueba.getEstadoPrueba() != EstadoPrueba.Pendiente) {
                    return "La prueba no está en estado pendiente para cancelarla.";
                }
                if ( _usuario_actual.getTipo() == TipoUsuario.GESTOR && _usuario_actual.getTipo() == TipoUsuario.MEDICO  )
                    prueba.setEstadoPrueba(EstadoPrueba.Cancelada);
                else //TipoUsuario.TECNICOPRUEBAS
                    prueba.setEstadoPrueba(EstadoPrueba.No_realizada);

                //Hacemos la actualizacion
                try {
                    Prueba.update(prueba);
                } catch (SQLException ex) {
                    System.out.println("cancelarPrueba.Fallo SQL:"+ex.getMessage());
                    return "Fallo de conexion con la base de datos.";
                }
            }
            
            return "Operacion realizada con exito";
        }

        /**
         * @brief Muestra las pruebas a realizar en el día de hoy.
         * @return Pruebas pendientes del tecnico
         * @throws IOException, ClassNotFoundException, ParseException, IDException, NoSuchAlgorithmException
         * @author Juan José Alonso Sánchez y Antonio M. Gutierrez Martinez
         */
        public static Prueba[] verPruebasPendientes(int idTecnicoPruebas) throws IOException,ClassNotFoundException, ParseException, IDException, NoSuchAlgorithmException {
            Prueba[] p = null;
            //DateFormat formato = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date ahora, fin;
            Calendar c = Calendar.getInstance();
            ahora = c.getTime();
            c.add(Calendar.HOUR, 9); //supongo pruebas de hasta 9 horas en adelante
            fin = c.getTime();
            
            try {
                p = Prueba.get(null, null,null, idTecnicoPruebas, EstadoPrueba.Pendiente,
                        null,null,fin);
            } catch (SQLException ex) {
               System.out.println("verPruebasPendientes.Fallo SQL:"+ex.getMessage());
            }

            return p;
        }

        /**
         * @brief Modificación del estado de una prueba.
         * @return NULL, si se modifica el estado de la prueba y un mensaje de error en caso contrario
         * @throws IOException, ClassNotFoundException, ParseException, IDException, NoSuchAlgorithmException
         * @author Juan José Alonso Sánchez y Antonio M. Gutierrez Martinez
         */
        public static String cambiarEstadoPrueba(int idPrueba , EstadoPrueba e)
                throws IOException,ClassNotFoundException, ParseException, IDException, NoSuchAlgorithmException {
            Prueba p = null;
            try {
                p = Prueba.get(idPrueba);
            } catch (SQLException ex) {
                System.out.println("cambiarEstadoPrueba.Fallo SQL:"+ex.getMessage());
               return "Fallo de conexion con la base de datos.";
            }
            if (p != null) { // Existe en la BD
                p.setEstadoPrueba(e);
                try {
                    Prueba.update(p);
                } catch (SQLException ex) {
                    System.out.println("cambiarEstadoPrueba.Fallo SQL:"+ex.getMessage());
                    return "Fallo de conexion con la base de datos.";
                }
            } else { //No existe en la BD
                return "La prueba no existe en la Base de Datos.";
            }
            
            return null;
        }

        /**
         * @brief Asignamos un resultado a una prueba del paciente
         * @return Una cadena con el error si algo sale mal. Null si todo sale bien.
         * @throws NoSuchAlgorithmException, ClassNotFoundException, IOException, IDException,
         * @author Juan José Alonso Sánchez y Antonio M. Gutierrez Martinez
         */
        public static String asignarResultados(Prueba p)
                throws SQLException,IOException, ClassNotFoundException, IDException, NoSuchAlgorithmException{

            //Asignamos datos de las pruebas
            p.setFechaResultados(Calendar.getInstance().getTime());
            try {
                Prueba.add(p);
            } catch (SQLException ex) {
                System.out.println("asignarResultados.Fallo SQL:"+ex.getMessage());
                return "Fallo de conexion con la base de datos.";
            }
            
            return null;
        }

        /**
         * @brief obtiene los valores prueba de un atributo de una prueba
         * @param name
         * @return Valor pruebas
         * @throws IOException, ClassNotFoundException, ParseException, IDException, NoSuchAlgorithmException
         * @author Antonio M. Gutierrez Martinez
         */
        public static ValoresPrueba obtenerValoresPrueba( String name )
                throws SQLException,IOException, ClassNotFoundException, IDException, NoSuchAlgorithmException{

            ValoresPrueba v = null;

            try {
                return ValoresPrueba.get(name);
            }catch (SQLException ex) {
                System.out.println("obtenerValoresPrueba.Fallo SQL:"+ex.getMessage());
            }
            
            return v;
        }

        public static ChartPanel graficaCita(Integer mes,ArrayList<String> error)  {

            CategoryDataset dataset;
            ChartPanel ret=null;


            try{
                if (mes<1 || mes>12 )
                    throw(new Exception("El mes tiene que estar entre 1 y 12"));
                dataset = Estadisticas.citaDia(mes);
                JFreeChart chart = createChart(dataset,"Citas por dia","Dias","Numero de dias");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch(Exception ex){
                
                error.add(ex.getMessage());
            }

            return ret;
        }

        public static ChartPanel graficaEdades( ArrayList<String> error)   {

            CategoryDataset dataset;
            ChartPanel ret=null;
            

            try{
                dataset = Estadisticas.pacientesEdad();
                JFreeChart chart = createChart(dataset,"Pacientes por edad","Años","Paciente");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }

            return ret;
        }

        public static ChartPanel graficaEdadesFrecuentes(ArrayList<String> error)  {


            DefaultPieDataset dataset;
            ChartPanel ret=null;
            

            try{
                dataset = Estadisticas.citaEdad();
               JFreeChart chart = createChart(dataset,"Proporcion de citas por edad");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }

            return ret;


        }

        public static ChartPanel graficaEmpleados(ArrayList<String> error)   {
            DefaultPieDataset dataset;
            ChartPanel ret=null;
            

            try{
                dataset = Estadisticas.empledosTipo();
                JFreeChart chart = createChart(dataset,"Proporcion de empleados por tipo");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }

            return ret;
        }

        public static ChartPanel graficaGenero(ArrayList<String> error)   {
            DefaultPieDataset dataset;
            ChartPanel ret=null;
            

            try{
                dataset = Estadisticas.generos();
                JFreeChart chart = createChart(dataset,"Proporcion de mujeres y hombres");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }

            return ret;

        }

        public static ChartPanel graficaPruebas(ArrayList<String> error)   {

            DefaultPieDataset dataset;
            ChartPanel ret=null;
            

            try{
                dataset = Estadisticas.prubasTipo();
               JFreeChart chart = createChart(dataset,"Proporcion de pruebas por tipo");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }

            return ret;
        }

        public static ChartPanel estadisticaMedico(Date inicio, Date fin, Integer tamanio, ArrayList<String> error)  {


            CategoryDataset dataset;
            ChartPanel ret=null;
            

            try{
                if(tamanio<0 || tamanio>30)
                    throw new Exception("El tamaño de los datos no es valido");

                if(inicio.compareTo(fin)>0)
                    throw new Exception("La fecha fin es mayor que la fecha inicion");

                dataset = Estadisticas.citaMedico(inicio, fin,tamanio);
                JFreeChart chart = createChart(dataset,"Grafica citas por medico","Médicos","Número de citas");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch (Exception ex){
                
                 error.add( ex.getMessage());
            }

            return ret;
        }

        public static ChartPanel estadisticaPaciente(Date inicio, Date fin, Integer tamanio, ArrayList<String> error)  {
            CategoryDataset dataset = null;
            ChartPanel ret=null;
            

            try{
                if(tamanio<0 || tamanio>30)
                    throw new Exception("El tamaño delos datos no es valido");
                if(inicio.compareTo(fin)>0)
                    throw new Exception("La fecha fin es mayor que la fecha inicion");

                dataset = Estadisticas.PacienteMedico(inicio, fin, tamanio);
                JFreeChart chart = createChart(dataset,"Grafica citas por paciente","Paciente","Número de citas");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch (Exception ex){
                
                 error.add( ex.getMessage());
            }

            return ret;
        }

         public static ChartPanel estadisticaFarmaco(Date inicio, Date fin, Integer tamanio, ArrayList<String> error)  {
           CategoryDataset dataset;
            ChartPanel ret=null;
            
            try{
                if(tamanio<0 || tamanio>30)
                    throw new Exception("El tamaño delos datos no es valido");
                if(inicio.compareTo(fin)>0)
                    throw new Exception("La fecha fin es mayor que la fecha inicion");

                dataset = Estadisticas.farmacoMasVendido(inicio, fin, tamanio);
                JFreeChart chart = createChart(dataset,"Grafica de medicamentos recetados","Medicamentos","Número de paquetes");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch (Exception ex){
                
                 error.add( ex.getMessage());
            }

            return ret;
        }

        public static ChartPanel estadisticaLote(Date inicio, Date fin, Integer tamanio, ArrayList<String> error)  {
            CategoryDataset dataset;
            ChartPanel ret=null;
            

            try{

                if(tamanio<0 || tamanio>30)
                    throw new Exception("El tamaño delos datos no es valido");
                if(inicio.compareTo(fin)>0)
                    throw new Exception("La fecha fin es mayor que la fecha inicion");

                dataset = Estadisticas.lote(inicio, fin, tamanio);
                JFreeChart chart = createChart(dataset,"Grafica cantidad de lotes","Lotes","Número de pedidos");
                ret = configura(chart);
            }
            catch(SQLException ex){
                
                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){
                
                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){
                
                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch (Exception ex){
                
                 error.add( ex.getMessage());
            }

            return ret;
        }

         public static ArrayList<ArrayList<String>> ListadoMedico(Date inicio, Date fin, Integer tamanio, ArrayList<String> error)  {


            ArrayList<ArrayList<String>> dataset=null;

            try{
                if(tamanio<0 || tamanio>30)
                    throw new Exception("El tamaño de los datos no es valido");

                if(inicio.compareTo(fin)>0)
                    throw new Exception("La fecha fin es mayor que la fecha inicion");

                dataset = Estadisticas.ListadoCitaMedico(inicio, fin,tamanio);

            }
            catch(SQLException ex){

                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){

                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){

                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch (Exception ex){

                 error.add( ex.getMessage());
            }

            return dataset;
        }

        public static ArrayList<ArrayList<String>> ListadoPaciente(Date inicio, Date fin, Integer tamanio, ArrayList<String> error)  {
            ArrayList<ArrayList<String>> dataset = null;


            try{
                if(tamanio<0 || tamanio>30)
                    throw new Exception("El tamaño delos datos no es valido");
                if(inicio.compareTo(fin)>0)
                    throw new Exception("La fecha fin es mayor que la fecha inicion");

                dataset = Estadisticas.ListadoPacienteMedico(inicio, fin, tamanio);

            }
            catch(SQLException ex){

                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){

                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){

                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch (Exception ex){

                 error.add( ex.getMessage());
            }

            return dataset;
        }

         public static ArrayList<ArrayList<String>> ListadoFarmaco(Date inicio, Date fin, Integer tamanio, ArrayList<String> error)  {
           ArrayList<ArrayList<String>> dataset=null;


            try{
                if(tamanio<0 || tamanio>30)
                    throw new Exception("El tamaño delos datos no es valido");
                if(inicio.compareTo(fin)>0)
                    throw new Exception("La fecha fin es mayor que la fecha inicion");

                dataset = Estadisticas.ListadoFarmacoMasVendido(inicio, fin, tamanio);

            }
            catch(SQLException ex){

                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){

                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){

                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch (Exception ex){

                 error.add( ex.getMessage());
            }

            return dataset;
        }

        public static ArrayList<ArrayList<String>> ListadoLote(Date inicio, Date fin, Integer tamanio, ArrayList<String> error)  {
            ArrayList<ArrayList<String>> dataset=null;


            try{

                if(tamanio<0 || tamanio>30)
                    throw new Exception("El tamaño delos datos no es valido");
                if(inicio.compareTo(fin)>0)
                    throw new Exception("La fecha fin es mayor que la fecha inicion");

                dataset = Estadisticas.ListadoLote(inicio, fin, tamanio);
            }
            catch(SQLException ex){

                error.add("Error en la Base de datos causado por: "+ex.getMessage());
            }catch (IOException ex){

                error.add("Error en acceso causado por: "+ex.getMessage());
            }
            catch(ClassNotFoundException ex){

                error.add("Error interno causado por: "+ex.getMessage());
            }
            catch (Exception ex){

                 error.add( ex.getMessage());
            }

            return dataset;
        }


        private static ChartPanel configura(JFreeChart chart){
            if(chart==null)
                return null;
            else{
                ChartPanel chartPanel = new ChartPanel(chart);
                chartPanel.setFillZoomRectangle(true);
                chartPanel.setMouseWheelEnabled(true);
                chartPanel.setRefreshBuffer(true);
                chartPanel.setPreferredSize(new Dimension(640, 480));


                return chartPanel;
            }
    }


        private static  JFreeChart createChart(DefaultPieDataset data, String titulo) {

            JFreeChart chart=null;

            if(data!=null){

                // create a chart...
                 chart = ChartFactory.createPieChart(
                    titulo,
                    data,
                    true, // legend?
                    true, // tooltips?
                    false // URLs?
                 );
            }

        /*
        BufferedImage b= chart.createBufferedImage(800, 600);
        b.getSource();
        File outputfile = new File("saved.png");
        ImageIO.write(b, "png", outputfile);
        */

        return chart;

        }

        private static JFreeChart createChart(CategoryDataset dataset, String titulo, String ordenadas, String abscisas) {
            // create the chart...

            if(dataset==null)
                return null;

            JFreeChart chart = ChartFactory.createBarChart(

                titulo,       // chart title
                ordenadas,               // domain axis label
                abscisas,                  // range axis label
                dataset,                  // data
                PlotOrientation.VERTICAL, // orientation
                true,                     // include legend
                true,                     // tooltips?
                false                     // URLs?
            );
            // set the background color for the chart...

            chart.setBackgroundPaint(SystemColor.window.getColor("window"));

            // get a reference to the plot for further customisation...
            CategoryPlot plot = (CategoryPlot) chart.getPlot();

            // set the range axis to display integers only...
            NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
            rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

            // disable bar outlines...
            BarRenderer renderer = (BarRenderer) plot.getRenderer();
            renderer.setDrawBarOutline(false);

           // set up gradient paints for series...
            GradientPaint gp0 = new GradientPaint(0.0f, 0.0f, Color.blue,
                    0.0f, 0.0f, new Color(0, 0, 64));
            GradientPaint gp1 = new GradientPaint(0.0f, 0.0f, Color.green,
                    0.0f, 0.0f, new Color(0, 64, 0));
            GradientPaint gp2 = new GradientPaint(0.0f, 0.0f, Color.red,
                    0.0f, 0.0f, new Color(64, 0, 0));
            renderer.setSeriesPaint(0, gp0);
            renderer.setSeriesPaint(1, gp1);
            renderer.setSeriesPaint(2, gp2);

            CategoryAxis domainAxis = plot.getDomainAxis();
            domainAxis.setCategoryLabelPositions(
                    CategoryLabelPositions.createUpRotationLabelPositions(
                           Math.PI / 6.0));
            // OPTIONAL CUSTOMISATION COMPLETED.

            return chart;
        }

        
}

